package com.gopay.scheduler.job;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.dps.DpsStaCode;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.dao.bank.BankOrderQueryDAO;
import com.gopay.common.cps.dao.order.CpsGeneralMainOrderQueryDAO;
import com.gopay.common.cps.dao.wallet.bouns.WaBounsMainOrderDao;
import com.gopay.common.cps.dao.wallet.prepaid.WaPrepaidOrderDtlDao;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.dps.WaBounsMainOrder;
import com.gopay.common.domain.dps.WaPrepaidOrderDtl;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.cron.dao.trans.MainOrderQueryDAO;
import com.gopay.remote.order.MainOrderField;
import com.gopay.remote.order.MainOrderUpdateRemoteService;
import com.gopay.scheduler.GopayBaseJob;

/**
 * 手机钱包超时订单处理任务（30000,30101）
 * <p/>
 * 1）30000 进行中    处理核心系统的超时订单，
 * 2）30101银行处理中 处理银行的超时订单，
 * <p/>
 * 针对的交易类型为 00500 01601,01602,01603,01605,01606,01608,01610,01611,01612
 * 1)普通的充值订单直接置为失效
 * 2)一笔充值订单，一笔支付订单的情况（01601,01602,01603,01605,01606,01608,01610,01611,01612）
 * 只对充值订单进行失效轮训，因为处于30000和30101状态下的支付订单所对应的充值订单必定是成功，
 * 如果做支付订单的失效轮训，那么充值订单的钱必须要退给客户。但是这个任务目前只做失效订单轮训，
 * 等待后来人完成支付订单轮训失效，充值订单退款的功能  todo
 * 所以 （01601,01602,01603,01605,01606,01608,01610,01611,01612）也是轮训其对应的充值订单（00500），
 * 如果充值失败那么就直接置为失效状态
 * <p/>
 * 目前超时时间定为12个小时。
 * <p/>
 * 针对的付款渠道 03：个人借记卡快捷   06：个人信用卡快捷   08：wap网银付款 （原来的定时任务没有这个通道，是01个人网银付款）
 * <p/>
 * Created by zhangjianlong on 2016/12/9. All Right reserved
 * 
 * 
 * 
 * modify by tangyang at 20170526
 * 增加快捷支付、wap网银支付订单进行中的失效轮询
 * GOPAY_INT_TXN_CD：01603,01605,01606,01607,01608,01611,01612,01613
 * PAY_CHANNEL:03、06、08
 * TXN_STA_CD：30000
 * 
 */
public class WalletCheckTimeoutOrderJob extends GopayBaseJob {

    private Logger logger = LoggerFactory
            .getLogger(WalletCheckTimeoutOrderJob.class);

    @Resource(name = "mainOrderQueryDAO")
    private MainOrderQueryDAO mainOrderQueryDAO;

    @Resource(name = "cpsGeneralMainOrderDAO")
    private CpsGeneralMainOrderQueryDAO cpsGeneralMainOrderDAO;
    @Resource(name = "bankOrderQueryDAO")
    private BankOrderQueryDAO bankOrderQueryDAO;
    
    @Resource(name = "cpsGeneralMainOrderOperClient")
    private MainOrderUpdateRemoteService cpsGeneralMainOrderOperClient;
    
    @Resource(name = "waBounsMainOrderDao")
    private WaBounsMainOrderDao waBounsMainOrderDao;
    
	@Resource(name = "waPrepaidOrderDtlDao")
	private WaPrepaidOrderDtlDao waPrepaidOrderDtlDao;

    @Override
    protected void doJobInternal() {
        List<Object[]> resultList = mainOrderQueryDAO.findWalletTimeoutCpsGenMainOrderByTimeSpan();
        this.logger.info("resultList发现{}条超时订单", resultList.size());
//        String txnStaCode = String.valueOf(TxnStaCode.TXN_STA_CD_20002.value);
//        Map<MainOrderField, String> map = new HashMap<MainOrderField, String>();
//        map.put(MainOrderField.TXN_STA_CD, txnStaCode);
//        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
//        map.put(MainOrderField.TRAN_FINISH_TIME, sf.format(new Date()));

        if (!resultList.isEmpty()) {

            this.logger.info("开始更新手机钱包超时订单");

            for (int i = 0; i < resultList.size(); i++) {

                Object[] objs = resultList.get(i);
                //如果关联订单为空
                if (null == objs[1] || "".equals(objs[1].toString())) {
                    String gopayOrderId = String.valueOf(objs[0]);
                    updateTxnStaCode20002(gopayOrderId);
                }
                // 关联订单为空
                else {
                    Map<String, String> orders = new HashMap<String, String>();
                    orders.put("orderId", (String) objs[0]);
                    orders.put("origOrderId", (String) objs[1]);
                    updateTxnStaCode20002(orders);
                }

            }
            this.logger.info("更新手机钱包超时订单结束");
        }
        
        /*
         * 订单失效的处理
         * gopay_int_txn_cd in ('01603','01605','01606','01607','01608','01611','01612','01613')  
         * pay_channel in ('03','06','08') 
         * txn_sta_cd='30000' 
         * gateway_source = '05' 
         * 
         */
        List<Object[]> resultList2 = mainOrderQueryDAO.findWalletTimeoutOrderBank();
        this.logger.info("resultList2发现{}条超时订单", resultList2.size());
        if (!resultList2.isEmpty()) {
        	for (int i = 0; i < resultList2.size(); i++) {
        		Object[] objs = resultList2.get(i);
        		this.logger.info( i+"支付订单国付宝订单号=" + (String)objs[0]);
//        						+ ",支付订单状态=" + (BigDecimal)objs[1]
//        						+ ",支付订单对应的00500订单号=" + (String)objs[2]
//        						+ ",支付订单对应的00500订单状态=" + (BigDecimal)objs[3]
//        						+ ",00500订单错误原因=" + (String)objs[4]
//        						+ ",支付订单对应银行主订单号=" + (String)objs[5]
//        						+ ",支付订单对应银行主订单状态=" + (String)objs[6]
//        						+ ",支付订单对应银行主订单发往银行时间=" + (Date)objs[7]
//        						+ ",支付订单对应的00500订单对应银行主订单号=" + (String)objs[8]
//        						+ ",支付订单对应的00500订单对应银行主订单状态=" + (String)objs[9]
//        						+ ",支付订单对应的00500订单对应银行主订单发往银行时间=" + (Date)objs[10]);
        		//根据否存在00500订单，兼容先充值后支付的交易
        		CpsGenMainOrder mainOrder00500 = cpsGeneralMainOrderDAO.findByRelevanceGopayOrderId((String)objs[0]);
        		
        		if(mainOrder00500!=null){
        			//若00500订单状态为进行中（30000 或 30101）
        			logger.info("---00500GopayOrderId=" + mainOrder00500.getGopayOrderId() + ",00500TxnStaCd=" + mainOrder00500.getTxnStaCd());
        			if(TxnStaCode.TXN_STA_CD_30000.value == mainOrder00500.getTxnStaCd()
        					|| TxnStaCode.TXN_STA_CD_30101.value == mainOrder00500.getTxnStaCd()){
        				/*
        				 * 支付订单对应的00500订单对应银行主订单号为空，即没有银行订单
        				 * 将充值订单更新为20002，将支付订单更新为20002
        				 * 
        				 */
        				BankOrder bankOrder= bankOrderQueryDAO.getCheckOrderByGopayOrderId(mainOrder00500.getGopayOrderId());
        				if(bankOrder==null ){
        					Map<String, String> orders = new HashMap<String, String>();
        			        orders.put("orderId", (String) objs[0]);
        			        orders.put("origOrderId", mainOrder00500.getGopayOrderId());
        			        updateTxnStaCode20002(orders);
        			        continue;
        				}
        				
        				logger.info("00500OrderStatus" + bankOrder.getOrderStatus() + ",SendBankTm=" + bankOrder.getSendBankTm());
        				/*
        				 * 支付订单对应的00500订单对应银行主订单状态为00
        				 * 91- 银行通知订单失败
        				 * 99- 其他失败
        				 * 将充值订单更新为20002，将支付订单更新为20002
        				 */
        				
        				if(BankOrderStatus.ORDER_FAIL.equals(bankOrder.getOrderStatus())
        						||BankOrderStatus.BPS_CHECK_FAIL.equals(bankOrder.getOrderStatus())){
        					Map<String, String> orders = new HashMap<String, String>();
        			        orders.put("orderId", (String) objs[0]);
        			        orders.put("origOrderId", mainOrder00500.getGopayOrderId());
        			        updateTxnStaCode20002(orders);
        			        continue;
        				}
        				/*
        				 * 支付订单对应的00500订单对应银行主订单状态为
        				 * 00- 进行中
        				 * 且发往银行时间大于24小时
        				 * 将充值订单更新为20002，将支付订单更新为20002
        				 */
        				
        				//当前时间-1
        				Date yesDate = DateUtils.add(DateUtils.getSystemDate(), Calendar.DATE, -1);
        				if(BankOrderStatus.PROCESS.equals(bankOrder.getOrderStatus())
        						&& bankOrder.getSendBankTm().before(yesDate)){
        					Map<String, String> orders = new HashMap<String, String>();
        			        orders.put("orderId", (String) objs[0]);
        			        orders.put("origOrderId", mainOrder00500.getGopayOrderId());
        			        updateTxnStaCode20002(orders);
        			        continue;
        				}
        				
        			}else{//若00500订单状态非30000 或 30101
        				//00500订单状态更新到主订单状态中
        				if( mainOrder00500.getTxnStaCd()==TxnStaCode.TXN_STA_CD_20001.value
        						|| mainOrder00500.getTxnStaCd()==TxnStaCode.TXN_STA_CD_20002.value
        						|| mainOrder00500.getTxnStaCd()==TxnStaCode.TXN_STA_CD_20003.value
        						|| mainOrder00500.getTxnStaCd()==TxnStaCode.TXN_STA_CD_20004.value
        						|| mainOrder00500.getTxnStaCd()>=TxnStaCode.TXN_STA_CD_90000.value){
	        		        Map<MainOrderField, String> map = new HashMap<MainOrderField, String>();
	        		        map.put(MainOrderField.TXN_STA_CD, mainOrder00500.getTxnStaCd()+"");
	        		        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
	        		        map.put(MainOrderField.TRAN_FINISH_TIME, sf.format(new Date()));
	        		        if(StringUtils.isNotBlank(mainOrder00500.getErrMsg())){
	        		        	map.put(MainOrderField.ERR_MSG, mainOrder00500.getErrMsg());
	        		        }
	        		        logger.info("---订单id为" + (String) objs[0] + "订单状态置为" + mainOrder00500.getTxnStaCd());
	        		        try {
	        		            cpsGeneralMainOrderOperClient.updateMany((String) objs[0], map);
	        		        } catch (GopayException e) {
	        		            this.logger.error("订单更新状态失败,要更新的订单id为"+(String) objs[0], e);
	        		        } catch (Exception e) {
	        		            this.logger.error("订单更新状态,系统失败,要更新的订单id为"+(String)objs[0], e);
	        		        }
        				}
        			}
        		}else{//不存在00500订单
        			/*
    				 * 支付订单对应银行主订单号为空，即没有银行订单
    				 * 将支付订单更新为20002
    				 * 
    				 */
        			BankOrder bankOrder= bankOrderQueryDAO.getCheckOrderByGopayOrderId((String)objs[0]);
        			if(bankOrder==null){
    			        updateTxnStaCode20002((String)objs[0]);
    			        updateWalletOrder20002(objs);
    			        continue;
    				}
        			/*
    				 * 支付订单对应银行主订单状态为00
    				 * 91- 银行通知订单失败
    				 * 99- 其他失败
    				 * 将支付订单更新为20002
    				 */
    				logger.info("00500OrderStatus" + bankOrder.getOrderStatus() + ",SendBankTm=" + bankOrder.getSendBankTm());

        			if(BankOrderStatus.ORDER_FAIL.equals(bankOrder.getOrderStatus())
    						||BankOrderStatus.BPS_CHECK_FAIL.equals(bankOrder.getOrderStatus())){
    			        updateTxnStaCode20002((String)objs[0]);
    			        updateWalletOrder20002(objs);
    			        continue;
    				}
    				/*
    				 * 支付订单对应银行主订单状态为
    				 * 00- 进行中
    				 * 且发往银行时间大于24小时
    				 * 将支付订单更新为20002
    				 */
    				    				
    				//当前时间-1
    				Date yesDate = DateUtils.add(DateUtils.getSystemDate(), Calendar.DATE, -1);
    				if(BankOrderStatus.PROCESS.equals(bankOrder.getOrderStatus())
    						&& bankOrder.getSendBankTm().before(yesDate)){
    			        updateTxnStaCode20002((String)objs[0]);
    			        updateWalletOrder20002(objs);
    			        continue;
    				}
        		}
        		
        		
        		
        	}
        }
        
        /*
         * 余额支付的状态为进行中（30000）的钱包交易，订单失效的处理
         * 00800、01603、01605、01606、01607、01608、01611、01612、01613
         * 账务表没有记录,置为20002
         */
        List<Object[]> resultList3 = mainOrderQueryDAO.findWalletTimeoutOrderGfb();
        this.logger.info("resultList3发现{}条超时订单", resultList3.size());
        if (!resultList3.isEmpty()) {
        	for (int i = 0; i < resultList3.size(); i++) {
        		Object[] objs = resultList3.get(i);
        		this.logger.info( i+"支付订单国付宝订单号=" + (String)objs[0]
        						+ ",订单明细表记录条数=" + (BigDecimal)objs[1]
        						+ ",订单交易码=" + (BigDecimal)objs[2]);
        		if(((BigDecimal)objs[1]).intValue() == 0){
        			updateTxnStaCode20002((String)objs[0]);
        			//add by zhoupeng 20170710 对业务订单进行更新  start
        			updateWalletOrder20002(objs);
        			//add by zhoupeng 20170710 对业务订单进行更新  end
        		}
        	}
        }
    }
    
    /**
     * 将多笔订单状态更新为20002
     * @param orders
     */
    private void updateTxnStaCode20002(Map<String, String> orders){
        String txnStaCode = String.valueOf(TxnStaCode.TXN_STA_CD_20002.value);
        Map<MainOrderField, String> map = new HashMap<MainOrderField, String>();
        map.put(MainOrderField.TXN_STA_CD, txnStaCode);
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        map.put(MainOrderField.TRAN_FINISH_TIME, sf.format(new Date()));
        map.put(MainOrderField.ERR_MSG, "订单已过期");
        logger.info("---订单id为" + orders + "订单置为失效");
        try {
            cpsGeneralMainOrderOperClient.updateMany(orders, map);
        } catch (GopayException e) {
            this.logger.error("订单更新状态失败,要更新的订单id为"+orders, e);
        } catch (Exception e) {
            this.logger.error("订单更新状态,系统失败,要更新的订单id为"+orders, e);
        }
    }
    
	private void updateWalletOrder20002(Object[] objs) {
		try {
			if (IntTxnCd._01608.value.equals((String) objs[2])) {
				WaBounsMainOrder waBounsMainOrder = waBounsMainOrderDao.queryByGopayOrderId((String) objs[0]);
				if (waBounsMainOrder != null) {
					waBounsMainOrder.setBounsStaCd(DpsStaCode.DPS_STA_CD_20002.value);
					waBounsMainOrder.setUpdateTime(new Date());
					waBounsMainOrderDao.update(waBounsMainOrder);
				}
			} else if (IntTxnCd._01611.value.equals((String) objs[2]) || IntTxnCd._01612.value.equals((String) objs[2])
					|| IntTxnCd._01613.value.equals((String) objs[2])
					|| IntTxnCd._01618.value.equals((String) objs[2])) {
				WaPrepaidOrderDtl pOrderDtl = waPrepaidOrderDtlDao.find(WaPrepaidOrderDtl.class, (String) objs[0]);
				if (pOrderDtl != null) {
					pOrderDtl.setRechargeStatus(DpsStaCode.DPS_STA_CD_20002.value);
					pOrderDtl.setUpdateTs(new Date());
					waPrepaidOrderDtlDao.update(pOrderDtl);
				}
			}
		} catch (Exception e) {
			this.logger.error("订单更新状态,系统失败,要更新的订单id为" + (String) objs[0], e);
		}
	}
    
    /**
     * 将单笔订单状态更新为20002
     * @param orders
     */
    private void updateTxnStaCode20002(String order){
        String txnStaCode = String.valueOf(TxnStaCode.TXN_STA_CD_20002.value);
        Map<MainOrderField, String> map = new HashMap<MainOrderField, String>();
        map.put(MainOrderField.TXN_STA_CD, txnStaCode);
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        map.put(MainOrderField.TRAN_FINISH_TIME, sf.format(new Date()));
        map.put(MainOrderField.ERR_MSG, "订单已过期");
        logger.info("---订单id为" + order + "订单置为失效");
        try {
            cpsGeneralMainOrderOperClient.updateMany(order, map);
        } catch (GopayException e) {
            this.logger.error("订单更新状态失败,要更新的订单id为"+order, e);
        } catch (Exception e) {
            this.logger.error("订单更新状态,系统失败,要更新的订单id为"+order, e);
        }
    }
}
